package com.htfyun.factorytest.engineer_test;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.os.Bundle;
import android.os.Message;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

import androidx.annotation.Nullable;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.List;

import com.blankj.utilcode.util.VolumeUtils;
import com.htfyun.factorytest.R;
import com.htfyun.factorytest.common.FTUtils;
import com.htfyun.factorytest.myrecorder.RecorderThread;
import com.htfyun.factorytest.playerutils.MyPlayRunnable;
import com.htfyun.factorytest.utils.DebugLog;
import com.htfyun.factorytest.utils.executor.AppExecutors;

public class FragmentES7210 extends BaseFragment implements View.OnClickListener{
    private static final String RECORDER_FILE_PATH = FTUtils.getFTStorageDirectory() + File.separator + "mic_es7210.pcm";

    private final int MIC_CHANNEL_COUNT = 2;
    //4通道声音
    private List<ByteBuffer> channelDataList = new ArrayList<>(MIC_CHANNEL_COUNT);

    private final int SampleRateInHz = 16000;

    private int playCount = 0;

    private OnBtnResultForES7210 onBtnResultForES7210;

    public void setOnBtnResultForES7210(OnBtnResultForES7210 onBtnResultForES7210) {
        this.onBtnResultForES7210 = onBtnResultForES7210;
    }

    @Override
    protected int getLayoutRes() {
        return R.layout.fragment_engineer_es7210;
    }

    @Override
    protected void onInitView(@Nullable Bundle savedInstanceState) {

        initBtn(R.id.btnRecord);
        initBtn(R.id.btnChannel1);
        initBtn(R.id.btnChannel2);

        initBtn(R.id.btnFail);
        initBtn(R.id.btnPass);

        setViewGone(R.id.btnChannel3);
        setViewGone(R.id.btnChannel4);

        setLayoutBtnVisibility(false);
        updateBtnRecord();

        DebugLog.e("channelDataList size  = " + channelDataList.size());

        VolumeUtils.setVolume(AudioManager.STREAM_MUSIC, VolumeUtils.getMaxVolume(AudioManager.STREAM_MUSIC), 0);

    }

    private volatile boolean isHeadsetRegistered = false;
    @Override
    protected void onVisible() {
        super.onVisible();

        if (!isHeadsetRegistered) {
            isHeadsetRegistered = true;
            //发送广播检测耳机插入状态
            IntentFilter filter = new IntentFilter(Intent.ACTION_HEADSET_PLUG);
            mContext.registerReceiver(headsetPlugReceiver, filter);
        }
    }

    @Override
    protected void onInvisible() {
        super.onInvisible();
        doStopRecord();

        if (isHeadsetRegistered) {
            isHeadsetRegistered = false;
            mContext.unregisterReceiver(headsetPlugReceiver);
        }
    }

    @Override
    public void onClick(View v) {

        int micIndex = -1;
        switch (v.getId()) {
            case R.id.btnRecord:
                clickBtnRecorder();
                break;
            case R.id.btnChannel1:
                micIndex = 0;
                break;
            case R.id.btnChannel2:
                micIndex = 1;
                break;
            case R.id.btnChannel3:
                micIndex = 2;
                break;
            case R.id.btnChannel4:
                micIndex = 3;
                break;
            case R.id.btnFail:
            case R.id.btnPass:

                if (onBtnResultForES7210 != null) {
                    onBtnResultForES7210.onBtnResultForES7210(v.getId() == R.id.btnPass);
                    findViewById(R.id.btnFail).setSelected(false);
                    findViewById(R.id.btnPass).setSelected(false);
                    v.setSelected(true);
                }
                return;
        }

        if (micIndex >= 0 ) {
            if ( micIndex < channelDataList.size()) {
                ByteBuffer byteBuffer = channelDataList.get(micIndex);
                if (byteBuffer != null) {
                    AppExecutors.runOnIoThread(new MyPlayRunnable(byteBuffer.array(),
                            AudioFormat.CHANNEL_OUT_MONO, onPlayOverCallback));
                    if (v instanceof Button) {
                        Button btn = (Button) v;
                        DebugLog.e(" micIndex = " + micIndex + ", btn.getText() = " + btn.getText());
                        if (getContext() != null) {
                            updateStatus((getString(R.string.mic_status_playing_mic_sound, btn.getText())));
                        }
                    }
                }
            } else {
                Toast.makeText(getContext(), R.string.mic_please_record, Toast.LENGTH_SHORT).show();
            }
        }

    }


    private void setLayoutBtnVisibility(boolean visibility) {
        View layoutBtn = findViewById(R.id.layoutBtn);
        if (layoutBtn == null) {
            return;
        }
        layoutBtn.setVisibility(visibility ? View.VISIBLE : View.INVISIBLE);
    }

    private void doUpdateStatus(String status) {
        TextView txtStatus = (TextView) findViewById(R.id.txtStatus);
        if (txtStatus == null) {
            return;
        }
        txtStatus.setText(status);
    }

    private void updateStatus(String status) {
        getHandler().obtainMessage(MSG_UPDATE_STATUS, status).sendToTarget();
    }
    private void updateStatus(int statusRes) {
        if (isFragmentVisible()) {
            String status = getString(statusRes);
            getHandler().obtainMessage(MSG_UPDATE_STATUS, status).sendToTarget();
        }
    }

    private void doStopRecord() {
        stopTestRecord();
        AppExecutors.runOnIoThread(parseMicDataRunnable);

        getHandler().removeMessages(MSG_MAX_RECORD_TIME);

        updateStatus(R.string.mic_status_recording_stop);
    }

    private void doStartRecord() {
        startTestRecord();
        setLayoutBtnVisibility(false);
        getHandler().sendEmptyMessageDelayed(MSG_MAX_RECORD_TIME, TIME_MAX_RECORD);

        updateStatus(R.string.mic_status_recording);
    }

    private void clickBtnRecorder() {
        if (recorderThread != null) {

            doStopRecord();

        } else {

            doStartRecord();

        }

        updateBtnRecord();
    }

    private void setViewGone(int resId) {
        View view = findViewById(resId);
        if (view != null) {
            view.setVisibility(View.GONE);
        }
    }

    private void initBtn(int resId) {
        View view = findViewById(resId);
        if (view != null) {
            view.setOnClickListener(this);
        }
    }

    private void updateBtnRecord() {
        Button btnRecord = (Button) findViewById(R.id.btnRecord);
        if (btnRecord == null) {
            return;
        }
        if (recorderThread != null) {
            btnRecord.setText(R.string.record_stop);
        } else {
            btnRecord.setText(R.string.record_start);
        }
    }

    private void setBtnRecordEnabled(boolean enabled) {
        Button btnRecord = (Button) findViewById(R.id.btnRecord);
        if (btnRecord == null) {
            return;
        }
        btnRecord.setEnabled(enabled);
    }

    private MyPlayRunnable.OnPlayOverCallback onPlayOverCallback =
            new MyPlayRunnable.OnPlayOverCallback() {
                @Override
                public void onPlayOverCallback() {
                    updateStatus(R.string.mic_status_playing_stop);
                    getHandler().sendEmptyMessage(MSG_SHOW_BTN);
                }
            };

    //////////////////////////
    // 解析 4 路mic数据
    /////////////////////////
    private final int MAX_RECORD_SIZE = 12 * 1024 * 1024;//12M
    private Runnable parseMicDataRunnable = new Runnable() {
        @Override
        public void run() {

            File recordFile = new File(RECORDER_FILE_PATH);
            if (!recordFile.exists()) {
                updateStatus(R.string.record_file_not_exist);
                return;
            }

            InputStream read = null;
            int fileSize = 0;
            int readSize = 0;
            try {
                byte[] readBuffer = new byte[MIC_CHANNEL_COUNT * 128];
                read = new FileInputStream(recordFile);
                fileSize = read.available();

                if (fileSize > MAX_RECORD_SIZE) {
                    fileSize = MAX_RECORD_SIZE;
                }

                DebugLog.e("fileSize = " + fileSize);

                channelDataList.clear();
                for (int i = 0; i < MIC_CHANNEL_COUNT; i++) {
                    ByteBuffer bb = ByteBuffer.allocate(fileSize / MIC_CHANNEL_COUNT / 2);
                    bb.order(ByteOrder.LITTLE_ENDIAN);
                    channelDataList.add(bb);
                }

                DebugLog.e("channelDataList size  = " + channelDataList.size());


                int length = 0;
                while ((length = read.read(readBuffer)) != -1) {
                    readSize += length;
                    if (0 != length % MIC_CHANNEL_COUNT) {
                        break;
                    }

                    for (int n = 0; n < length; ) {
                        for (int i = 0; i < MIC_CHANNEL_COUNT; i++) {
                            n++;
                            n++;
                            channelDataList.get(i).put(readBuffer[n++]);
                            channelDataList.get(i).put(readBuffer[n++]);
                        }
                    }

                    if (readSize >= fileSize) {
                        break;
                    }

                }

                String path = FTUtils.getFTStorageDirectory() + File.separator;
                int i = 0;
                for (ByteBuffer byteBuffer : channelDataList) {
                    saveByteBuffer(byteBuffer, path + i + ".pcm");
                    i++;
                }

            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

            getHandler().sendEmptyMessage(MSG_PARSE_RECORD_FILE_OVER);

        }
    };

    private void saveByteBuffer(ByteBuffer byteBuffer, String filePath) {
        FileOutputStream fos = null;
        try {
            File file = new File(filePath);
            if (file.exists()) {
                file.delete();
            }
            file.createNewFile();
            fos = new FileOutputStream(file);// 建立一个可存取字节的文件
        } catch (Exception e) {
            e.printStackTrace();
            fos = null;
        }

        if (fos != null) {
            try {
                fos.write(byteBuffer.array());
            } catch (IOException e) {
                e.printStackTrace();
            }finally {
                try {
                    fos.close();// 关闭写入流
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    //////////////////////
    //    Recorder
    /////////////////////
    private RecorderThread recorderThread;


    public void startTestRecord() {
        startRecordTread();
    }

    private void stopTestRecord() {
        stopRecordThread();

    }

    private void startRecordTread() {

        if (recorderThread != null) {
            stopRecordThread();
        }

        recorderThread = new RecorderThread("es7210-", null, RECORDER_FILE_PATH);
        recorderThread.getRecorderOperator().setSampleRateInHz(SampleRateInHz);
        recorderThread.getRecorderOperator().setChannelConfig(AudioFormat.CHANNEL_IN_STEREO);
        recorderThread.getRecorderOperator().setAudioFormat(AudioFormat.ENCODING_PCM_FLOAT);

        recorderThread.start();

    }

    private void stopRecordThread() {

        if (recorderThread != null) {
            recorderThread.joinThread();
            recorderThread = null;
        }
    }

    private BroadcastReceiver headsetPlugReceiver = new BroadcastReceiver() {

        @Override
        public void onReceive(Context context, Intent intent) {
            final String action = intent.getAction();

            if (action != null && action.equals(Intent.ACTION_HEADSET_PLUG)) {
                if (intent.hasExtra("state")) {
                    boolean unplug = (intent.getIntExtra("state", 0) == 0);
                    DebugLog.e("unplug = " + unplug);

                    setBtnRecordEnabled(unplug);

                }
            }
        }
    };


    private final int MSG_SHOW_BTN = 99;
    private final int MSG_UPDATE_STATUS = 100;
    private final int MSG_PARSE_RECORD_FILE_OVER = 101;
    private final int MSG_MAX_RECORD_TIME = 1000;
    private final int TIME_MAX_RECORD = 5 * 60 * 1000; // 5min
    @Override
    protected void handleMessage(Message msg) {
        super.handleMessage(msg);
        switch (msg.what) {
            case MSG_SHOW_BTN:
                setLayoutBtnVisibility(true);
                break;
            case MSG_UPDATE_STATUS:
                if (msg.obj instanceof String) {
                    doUpdateStatus((String) msg.obj);
                }
                break;
            case MSG_PARSE_RECORD_FILE_OVER:
//                setLayoutBtnVisible(true);
                if (getContext() != null) {
                    doUpdateStatus(getString(R.string.record_file_parse_over));
                }
                break;
            case MSG_MAX_RECORD_TIME:
                doStopRecord();
                break;
        }
    }

}
